Bitcoin のチェーン間のハッシュパワーの比較に使われる nChainWork の計算方法
nChainWork は CBlockIndex クラスのフィールドで、あるブロックがつながっているチェーンにおいて、そのブロックの採掘までにかけられた全てのマイニングの手間の合計を示す値です。
nChainWork はチェーンが分岐した際に、より強いチェーンを正当とするための判定に使われます。ノードはたとえプロトコル上有効なブロックであったとしても、自身のチェーンの先端ブロックよりもこの値が小さい場合はそのブロックを受け取りません。また、nMinimumChainWork という値がハードコーディングされていて、これより小さい nChainWork のブロックしか持っていないノードは端から相手にせずに接続を切られる、つまり明らかにおかしなノードを判別するための値としても使われています。 以下のコードで計算されています。
code:cpp
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
計算している箇所
pindexNew->pprev は前のブロックへのポインタですが、前のブロックが無いのは genesis block だけなので、大抵の場合は前のブロックの nChainWork にそのブロックの BlockProof(ハッシュパワーみたいなもの)を足す計算になります。
BlockProof の計算
BlockProof は個別のブロックに対するマイニング計算の大変さを表す値です。よく使われるハッシュパワーという言葉と似た概念ですが、ハッシュパワーが hash / sec の単位で表されるのに対して、BlockProof は以下の式で求められます。
BlockProof = 2**256 / (bnTarget+1)
bnTarget はこのブロックにおけるマイニングの目指すべき値です。マイナーはブロックのハッシュ値が bnTarget より小さい値になるように nonce を変えながらハッシュ計算を繰り返します。この bnTarget はブロックの中には nBits というフィールドにコンパクトな値に変換されて格納されています。
この式からわかるのは BlockProof は bnTarget の値に反比例しているということです。つまり bnTarget が小さくなる(難易度が上がる)ごとに BlockProof の値は大きくなります。
実装
code:cpp
arith_uint256 GetBlockProof(const CBlockIndex& block)
{
arith_uint256 bnTarget;
bool fNegative;
bool fOverflow;
bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
if (fNegative || fOverflow || bnTarget == 0)
return 0;
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
// as it's too large for an arith_uint256. However, as 2**256 is at least as large
// as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
// or ~bnTarget / (bnTarget+1) + 1.
return (~bnTarget / (bnTarget + 1)) + 1;
}
実際に計算している処理は以下です。
code:cpp
(~bnTarget / (bnTarget + 1)) + 1;
コメントにもあるように、 2**256 はとても巨大な値で、そのままでは扱えないため、~bnTarget に近似しています。~bnTarget は bnTarget のビット反転であるため、例えば bnTarget が
0x00000000FFFF0000000000000000000000000000000000000000000000000000
のとき、
0xFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
となって、ほぼ 2*256 と同じ値として使っても差し支えが無いという話のようです。
ちなみに、arith_uint256 という型は Bitcoin Core の中で定義されている 256bit の整数値を扱うための型で、秘密鍵やハッシュ値など 256bit のデータを扱う事が多い事情からとても多くの処理で使われているものです。